超级好用的流程库 - ggEditor

在一些中后台应用的开发中,有些业务往往需要用到流程设计器,比如:管理网络、审批流程等等...正是因为有多种业务都需要使用到流程图的功能,所以对于能快速产出一个流程设计器是非常必须的

工具选择

古话说的好,预先善其事,必先利其器。所以首先要做的就是选择一个合适的开源基础库,站在巨人的肩膀上,总是跑的更快

开源时代,社区的资源总是非常丰富,身为小程序媛的我漏出幸福的微笑😊

  • joint.js 支持多种交互式图表创建,但有收费版本和免费版本的区分,更丰富的功能可能就需要收费了
  • jsPlumb 是一套完全开源的流程图创建工具,上手简单,底层是基于 Canvas 技术,但唯一美中不足的是,基于 jQuery,所以对于大批量流程的操作,在性能上可能不能达到最佳
  • d3 d3 应该很多人都熟悉,非常好的可视化基础库,相应的,上手成本相对高一些
  • spritejs 同样是基于 Canvas,据说是月影大大一个人写的(✨✨眼),官网写的超好啦...
  • ggEditor 蚂蚁金服数据可视化团队的大神高力结合 react + g6 开源的流程库,它的前身是 g6Editor,也是他们团队开源的产品,官方说法是学习成本太高,停止了对外支持。底层也是 Canvas 技术,虽然 ggEditor 目前开源的文档不多,但是潜力无穷,使用起来非常便捷,上手也比较简单,貌似是去年开源的,社区相对还没那么活跃,所以它的使用依然是一个摸索的过程

最终,我选择了 ggEditor,因为它完全开源,使用很简单,很轻量级,而且天然基于 react,非常完美

快速构建

引用 ggEditor

我们可以按照 github 上 ggEditor 的安装步骤操作

启动之后的界面效果可以参考:http://ggeditor.com/demo/#/flow

我们可以看到它的官方 demo 功能是比较齐全的,基本上已经实现了一个元素拖拽及元素属性编辑的完整功能

属性解析

我们知道整个流程编辑器基本可以分为三部分,一部分是左侧的元素面板区,另一部分是右侧的元素属性配置区,再就是中间的流程展示区,每个流程元素上可以有相应的事件响应

所以这里主要介绍以上相应的属性

  • Item 节点配置

    • 其中 type 有 node 和 edge 两个值可选,node 就是节点,edge 是连接节点的连线,当我们初始化加载元素和保存导出元素数据时也是以这两种为key
    • shape 可选参数有:圆形 flow-circle | 圆角矩形 flow-rect | 菱形 flow-rhombus | 椭圆矩形 flow-capsule
    • src 可以引入一张图片作为当前节点的预览样式
    • 编辑器画板中的样式是由 model 决定,model 默认会继承 组件的 props.shapeprops.size,所以通常 model 只需配置 color、label。配置项如下:
      model: {
        color: '#333', // 节点主题色(选中颜色、激活颜色基于该值)
        size: [10, 10], // [x, y] 节点尺寸
        shape: 'cirle', // 图形:圆形 circle | 圆角矩形 rect | 菱形 rhombus | 椭圆矩形 capsule
        style: { // 关键形样式(可覆盖color的普通样式,但激活、选中依然无效,坑!)
          fill: 'red', // 填充背景
          stroke: 'blue' // 形状描边
        },
        label: { // 节点标签
          text: '开始节点', // 文本内容
          fill: 'green' // 文本颜色
        },
        index: 1 // 渲染层级
      }
      
  • Flow 编辑器配置
    组件上,最重要的是监听事件:
    js <Flow onNodeClick={(e) => { console.log(e); }}/>
    更多的我们可以参考页面事件 Page Events

    • 拖拽节点时,区分是新节点还是旧节点。可以用onDrop - 监听拖拽放置事件,如果是从元素面板区拖拽新节点到画布上,onDrop 返回的事件对象中 currentItemcurrentShape 都是 undefined。而如果是挪动旧节点的位置,这两个字段会记录拖动的图形图项。当然,也可以监听节点拖动结束事件 - onNodeDragEnd,这个事件只会在拖动画布上的节点时才触发

    • 锚点连线取消,比如有一个需求是当目标节点已经连线的时候,就取消连线。可以用 onAfterChange 事件,根据 item(type: 'edge') 或者 model(source:'xxxx') 对象中的参数进行判断。最后用结合异步函数和 <withPropsAPI> 组件取消连线:

      handleAddItem = (e) => {
        this.apiAction('undo')
      }
      
      apiAction = (command) => {
        const { propsAPI } = this.props
        setTimeout(() => {
          propsAPI.executeCommand(command)
        }, 0)
      }
      

      <withPropsAPI>是 ggEditor 自带的包装组件,同时它又自带 propsAPI 属性,更多的属性值我们可以参考 propsAPI

    • 保存数据。上面 <withPropsAPI> 提供的 propsAPI 属性中,包含了 save() 方法。我们可以封装一个 SaveButton 组件,暴露一个 onSave 事件,然后用 <withPropsAPI> 包装该组件。具体可参考 demo

    • 自定义键盘操作。可以通过监听 onKeyDownonKeyUp 手动创建多个快捷命令

      handleKeyUp = e => {
        // 键盘抬起时重置记录的按键
        this.keysDown = ''
      }
      
      handleKeyDown = e => {
        // 拼接按键命令
        if (this.keysDown.length === 0) {
          this.keysDown = e.domEvent.key
        } else {
          this.keysDown += `+${e.domEvent.key}`
        }
      
        // 自定义键盘操作
        switch (this.keysDown) {
          case 'Meta+c':
            this.diyCopyCommand()
            break
          case 'Control+c':
            this.diyCopyCommand()
            break
          case 'Meta+v':
            this.diyPasteCommand()
            break
          case 'Control+v':
            this.diyPasteCommand()
            break
          default: break
        }
      }
      
      // 自定义复制
      diyCopyCommand = () => {
        const { propsAPI } = this.props
        let selected = propsAPI.getSelected()
        if (selected.length > 0) {
          this.commandAction('copy')
        }
      }
      
      // 自定义粘贴
      diyPasteCommand = () => {
        this.commandAction('paste')
      }
      

以上只是 ggEditor 的核心组件和功能。还有很多组件没有提交,比如 <Minimap><ContextMenu><Toolbar> ,我们可以具体去看项目 demo

其他的属性解析可以参考官网 API

自定义节点

如果 <Item> 自带的参数不满足需求,可以使用 <ReisterNode> 来封装自己的 <Item>

比如自定义一个 start-node,就可以自行封装一个 node 组件

具体可以参考 Issues

兼容 IE11

ggEditor 是基于 umijs 脚手架的, umijs不得不说,太简单粗暴,默认不支持IE,如果需要支持,需要我们开启配置

需要在 .umirc.js 中配置

targets: {
  ie: 11,
}

dva 版本问题

Chrome warning

IE bug

查看后发现都是指向同一个问题,因为 dva 的最新版本,具体可以看看升级dva最新版提示Warning: Please use require("dva").dynamic instead of require("dva/dynamic"). Support for the latter will be removed in the next major release.2.6.0-beta.4 版本新抛出警告

为了快速解决这个问题,我去瞅了眼 ant-design-pro,发现它三天前提交的,但是dva版本仍是用的低版本,非常 nice

以上,便可快速解决 IE11 白屏的问题

参考文档

在 React 项目中引入 GG-Editor 编辑可视化流程

常见问题

PS:终于用上自己写的博客系统写文章啦,体验还是非常八错的 😊😊